/**
 * @file hoc.jsx.
 * @author liaoxuezhi@baidu.com
 */
/* eslint fecs-indent: [0, "space", 2, 2] */

import * as React from 'react';
import {
  PureComponent,
  PropTypes
} from "react";
import * as forEach from 'lodash/forEach';
import * as endsWith from 'lodash/endsWith';
import {evalExpression, evalExpression2} from '../renderer';
import * as assign from 'object-assign';

const returnFalse = () => false;

export const EnhanceAdvance = (options = {}) => ComposedComponent => class OnExpression extends PureComponent {
  static propTypes = {
    hideOn: PropTypes.string,
    disabledOn: PropTypes.string,
    detectPropName: PropTypes.string
  };

  static defaultProps = {
    detectPropName: 'data'
  };

  static contextTypes = {
    can: PropTypes.func
  };

  detects = {};
  expressions = {};
  constructor(props, context) {
    super(props, context);
    this.collectProps(props);
  }

  componentWillReceiveProps(nextProps) {
    this.collectProps(nextProps, this.props);
  }

  collectProps(props, prevProps) {
    const detects = this.detects;
    const expressions = this.expressions;

    forEach(props, (value, key) => {
      if (prevProps && prevProps[key] === value) {
        return;
      } else if (~['nameExpr', 'valueExpr', 'nameOn'].indexOf(key)) {
        console.warn(`${key} 不支持动态设置`);
        return;
      }

      if (typeof value === 'string' && endsWith(key, 'On')) {
        const field = key.substring(0, key.length - 2);
        value ? (detects[field] = evalExpression(value)) : (delete detects[field]);
      } else if (typeof value === 'string' && endsWith(key, 'Expr')) {
        const field = key.substring(0, key.length - 4);
        value ? (expressions[field] = value) : (delete expressions[field]);
      }
    });

    if (expressions['name'] || detects['name']) {
      console.warn(`valueExpr 会导致当前值没法修改`);
    }
  }

  render() {
    const {
      detectPropName,
      locals
    } = this.props;

    const additional = {};

    if (detectPropName) {
      const props = this.props;
      const data = props[detectPropName] || {};

      forEach(this.detects, (fn, key) => {
        additional[key] = !!(props[key] || fn(assign({}, locals, data, {acl: {can: this.context.can || returnFalse}})))
      });

      forEach(this.expressions, (expression, key) => {
        additional[key] = evalExpression2(expression, data, locals);
      });

      if (!options.ignoreVisible) {
        if (additional.hide || additional.hidden) {
          return null;
        } else if (additional.hasOwnProperty('visible') && !additional.visible) {
          return null;
        }
      }

    }

    return (
      <ComposedComponent
        {...this.props}
        {...additional}
      />
    )
  }
};
export const Enhance = ComposedComponent => EnhanceAdvance()(ComposedComponent);

export default Enhance;